/**
 * Copyright @2019 Josin All Rights Reserved.
 * Author: Josin
 * Email : xeapplee@gmail.com
 *
 * This is the very import file to get data from the MySQL little endian stream
 * Just doing it, to ensure the System's Little-Big endian rule.
 */

#include <endian.h>

/**
 * @brief NOTICE
 * This function will copy memory data from the given little_memory order with the given num
 */
long long exchange_copy_data_from_little(char *little_memory, int num)
{
    int           j, k;
    union {
    char      a[8];
    long long b:64;
    } Data;
    
    e_memzero(&Data, sizeof(Data));
    if ( big_endian() )
    {
        /**
         * @brief NOTICE
         * Big endian
         */
        for ( j = 0; j < num; j++ )
        {
            Data.a[j] = little_memory[j];
        }
    }
    else
    {
        /**
         * @brief NOTICE
         * Little endian
         */
        for ( j = 0, k = num; j < k; j++ )
        {
            Data.a[--num] = little_memory[j];
        }
    }
    return Data.b;
}

/**
 * @brief NOTICE
 * This function will copy memory data from the given little_memory order with the given num
 */
long long copy_data_from_little(char *little_memory, int num)
{
    int           j, k;
    union {
    unsigned char a[8];
    long long     b:64;
    } Data;
    
    e_memzero(&Data, sizeof(Data));
    if ( big_endian() )
    {
        /**
         * @brief NOTICE
         * Big endian
         */
        for ( j = 0, k = num; j < k; j++ )
        {
            Data.a[--num] = little_memory[j];
        }
    }
    else
    {
        /**
         * @brief NOTICE
         * Little endian
         */
        
        for ( j = 0; j < num; j++ )
        {
            Data.a[j] = little_memory[j];
        }
    }
    return Data.b;
}


/**
 * @brief NOTICE
 * The following function will copy data into the correct order
 * according to your machine, to get the right value
 * users should be know that the os's copy memory function such as memcpy
 * will copy the data into in it's original order
 * In different machine, the bit different type occupy different width.
 * In my machine:
 * char(1)  short(2) int(4) float(4)  long(8)  double(8)  long double(16)
 *
 * The first parameter was the source stream order by little endian.
 * then will copy it to the right order according to your machine
 * and return the right value.
 */
long copy_number_from_little_stream(char *src, int num)
{
    /**
     * @brief NOTICE
     * For example: 0xAF5D, in little machine, need be ordered by 0x5DAF
     * but in big endian, it's order is 0xAF5D
     */
    int   i,  j;
    union {
    char  c[8];
    long  l:64;
    } NUM;
    
    e_memzero(&NUM, sizeof(NUM));
    
    if ( big_endian() )
    {
        for ( i = 0; i < num; ++i ) {
            e_copymem(&NUM.c[i], &src[i], sizeof(char));
        }
    } else {
        for ( i = 0, j = num - 1; i < num && j >= 0; ++i, j-- ){
            e_copymem(&NUM.c[j], &src[i], sizeof(char));
        }
    }
    return NUM.l;
}

long copy_number_from_big_stream(char *src, int num)
{
    /**
     * @brief NOTICE
     * For example: 0xAF5D, in little machine, need be ordered by 0x5DAF
     * but in big endian, it's order is 0xAF5D
     */
    int   i,  j;
    union {
    char  c[8];
    long  l:64;
    } NUM;
    
    e_memzero(&NUM, sizeof(NUM));
    
    if ( big_endian() )
    {
        for ( i = 0, j = num - 1; i < num && j >= 0; ++i, j-- ){
            e_copymem(&NUM.c[j], &src[i], sizeof(char));
        }
    } else {
        for ( i = 0; i < num; ++i ) {
            e_copymem(&NUM.c[i], &src[i], sizeof(char));
        }
    }
    return NUM.l;
}

double copy_double_from_little_stream(char *src, int num)
{
    union {
        unsigned char a[8];
        double        b;
    } UV;
    
    int         i, j;
    e_memzero(&UV, sizeof(UV));
    
    if ( big_endian() )
    {
        for ( i = 0, j = num - 1; i < num && j >= 0; ++i, j-- ){
            e_copymem(&UV.a[j], &src[i], sizeof(char));
        }
    }
    else
    {
        for ( i = 0; i < num; ++i )
        {
            e_copymem(&UV.a[i], &src[i], sizeof(char));
        }
    }
    return UV.b;
}

float copy_float_from_little_stream(char *src, int num)
{
    union {
    unsigned char a[4];
    float        b;
    } UV;
    
    int         i, j;
    e_memzero(&UV, sizeof(UV));
    
    if ( big_endian() )
    {
        for ( i = 0, j = num - 1; i < num && j >= 0; ++i, j-- ){
            e_copymem(&UV.a[j], &src[i], sizeof(char));
        }
    }
    else
    {
        for ( i = 0; i < num; ++i )
        {
            e_copymem(&UV.a[i], &src[i], sizeof(char));
        }
    }
    return UV.b;
}

long copy_number_from_bit( long num, int numbit, int begin_pos, int length )
{
/**
 * @brief NOTICE
 * This function is used to get the value from the given bitsets with the
 * begin position and length,[NOTICE: This function is begin_pos contains] for example:
 * 100|101|01011001
 * The bits between from 4 and 6(3) is 101, need to be shift right 8 bits  so the value is 5
 * 1001|0101|011001
 * The bits between from 5 and 8(4) is 0101, need to be shift right 6 bits so the value is also 5
 */
    return ( num >> (numbit - ( begin_pos + length - 1)) ) & ( ( 1 << length ) - 1);
}

long bitsets_in_var( int num )
{
    int bitsets = 0;
    
    while (num)
    {
        num = num & ( num - 1 );
        bitsets++;
    }
    return bitsets;
}